<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Pgwatch2 :: Metrics and preset configs</title>
    <link rel="stylesheet" href="/static/bootstrap-4.3.1-dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/custom.css">
</head>
<body>

<div class="container-fluid">

    <nav class="navbar navbar-expand-md navbar-light bg-light mb-2">

    <ul class="navbar-nav mr-auto">
        <li class="nav-item">
            <a class="nav-link" href="/"><h4>pgwatch2</h4></a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="https://www.cybertec-postgresql.com/en/"><img src="/static/logo.png" alt="Cybertec logo" height="40px"></a>
        </li>
    </ul>

    <ul class="navbar-nav ml-auto">
        <li class="nav-item">
            <a class="nav-link" href="/dbs">DBs</a>
        </li>
        <li class="nav-item active">
            <a class="nav-link" href="/metrics">Metric definitions</a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="/stats-summary" title="Hint - Grafana is the preferred metrics browser">Stats summary</a>
        </li>
        {% if not no_component_logs %}
        <li class="nav-item dropdown" title="Logs will open in a new window">
            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown">Logs</a>
            <div class="dropdown-menu dropdown-menu-right">
                <a class="dropdown-item" href="/logs/pgwatch2/200" target="_blank">Pgwatch2 [last 200 lines]</a>
                <a class="dropdown-item" href="/logs/influxdb/200" target="_blank">InfluxDB [last 200 lines]</a>
                <a class="dropdown-item" href="/logs/grafana/200" target="_blank">Grafana [last 200 lines]</a>
                <a class="dropdown-item" href="/logs/postgres/200" target="_blank">Postgres [last 200 lines]</a>
                <a class="dropdown-item" href="/logs/webui/200" target="_blank">Web UI [last 200 lines]</a>
                <a class="dropdown-item" href="/versions" target="_blank">Component versions</a>
            </div>
        </li>
        {% endif %}

        {% if no_anonymous_access and session['logged_in'] %}
        <li class="nav-item">
            <a class="nav-link" href="/logout">Logout</a>
        </li>
        {% endif %}

    </ul>
    </nav>

</div>

<div class="container-fluid">

{% if messages %}
    {% for message in messages: %}
    <div class="row">
        <div class="col alert alert-warning alert-dismissible fade show" role="alert">
            {{message}}
            <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
        </div>
    </div>
    {% endfor %}
{% endif %}

<h2>Preset configs</h2>

<div class="table-responsive">
    <table class="table table-striped">
        <thead>
            <tr>
                <td>Name</td>
                <td>Description</td>
                <td>Config JSON</td>
                <td>Active DBs using config</td>
                <td>Last modified</td>
                <td></td>
                <td></td>
            </tr>
        </thead>
        <tbody>
            {% for row in preset_configs: %}
            <tr>
                <form action="/metrics" method="post">
                    <td id="{{row['pc_name']|e}}">{{row['pc_name']|e}}<input type="hidden" name="pc_name" value="{{row['pc_name']}}"></td>
                    <td><textarea name="pc_description" cols="50">{{row['pc_description']|e}}</textarea></td>
                    <td><textarea name="pc_config" cols="50">{{row['pc_config']|e}}</textarea></td>
                    <td><a href="/dbs">{{row['active_dbs']}}</a></td>
                    <td>{{row['pc_last_modified_on']}}</td>
                    <td><input type="submit" name="save" value="Save"></td>
                    <td>{% if row['active_dbs'] == '' %}<input type="submit" name="delete" value="Delete">{% endif %}</td>
                </form>
            </tr>
            {% endfor %}
            <tr>
                <form action="/metrics" method="post">
                    <td><input type="text" id="pc_name" name="pc_name" value="" size="10"></td>
                    <td><input type="text" name="pc_description" value=""></td>
                    <td><textarea id="pc_config" name="pc_config" cols="50">{"metric": interval_seconds, ...}</textarea></td>
                    <td></td>
                    <td></td>
                    <td><input type="submit" id="new" name="new" value="New"></td>
                    <td></td>
                </form>
            </tr>
        </tbody>
    </table>

    <h2>Active metrics listing</h2>
    <ul>
    {% for m in metrics_list: %}
        <li style="display: inline"><b>{{m['m_name']}}</b> [ver: {{m['versions']}}]</li>
    {% endfor %}
    </ul>

</div>

<h2 title="Inactive at the bottom">Metric definitions</h2>

<div class="table-responsive">
    <table class="table table-striped">
        <thead>
            <tr>
                <td size="18">Metric</td>
                <td size="3">PG ver.<br/>from</td>
                <td title="NB! 'epoch_ns' column needs to be always present">SQL</td>
                <td title="Will be used instead of normal SQL if monitoring user is a superuser (recommended only on localhost usage) or if first try with normal SQL fails. Helps to avoid creating helper functions (aka altering the DB state in any way) for Postgres-native metrics">Privileged SQL</td>
                <td>Comment</td>
                <td>Is<br/>active?</td>
                <td title="Code for metric fetching helpers. Not to be used for normal metrics gathering">Is<br/>helper?</td>
                <td title="Execute only on masters">Master<br/>only?</td>
                <td title="Execute only on standbys">Standby<br/>only?</td>
                <td title="Metric attributes - will be applied to all version definitions">Metric attributes</td>
                <td title="Column attributes. Use to specify Prometheus Gauge type columns. 'Gauge' means non-cumulative columns.">Column attributes</td>
                <td title="Config server TZ">Last modified</td>
                <td></td>
                <td></td>
            </tr>
        </thead>
        <tbody>
            {% for row in metric_definitions: %}
            <tr>
                <form action="/metrics" method="post">
                    <td>
                        <input type="hidden" name="m_id" value="{{row['m_id']}}">
                        <input type="text" size="18" name="m_name" value="{{row['m_name']|e}}" title="Metric name. Lowercase alphanumerics and underscores allowed." pattern="[a-z0-9_\.]+">
                    </td>
                    <td><input type="text" size="3" name="m_pg_version_from" value="{{row['m_pg_version_from']}}" title="Version from"></td>
                    <td><textarea name="m_sql" cols="35" title="SQL for metric">{{row['m_sql']}}</textarea></td>
                    <td><textarea name="m_sql_su" cols="35" title="Privileged (superuser or pg_monitor grant) SQL for metric">{{row['m_sql_su']}}</textarea></td>
                    <td><input type="text" size="12" name="m_comment" value="{{row['m_comment']}}" title="Comment"></td>
                    <td><input type="checkbox" name="m_is_active" {% if row['m_is_active'] %}checked{% endif %} title="Is active?"></td>
                    <td><input type="checkbox" name="m_is_helper" {% if row['m_is_helper'] %}checked{% endif %} title="Is helper?"></td>
                    <td><input type="checkbox" name="m_master_only" {% if row['m_master_only'] %}checked{% endif %} title="Master only?"></td>
                    <td><input type="checkbox" name="m_standby_only" {% if row['m_standby_only'] %}checked{% endif %} title="Standby only?"></td>
                    <td><textarea name="ma_metric_attrs" cols="20" title="Metric attributes - will be applied to all version definitions">{{row['ma_metric_attrs']}}</textarea></td>
                    <td><textarea name="m_column_attrs" cols="30" title="Column attributes. Use to specify Prometheus Gauge type columns. 'Gauge' means non-cumulative columns.">{{row['m_column_attrs']}}</textarea></td>
                    <td>{{row['m_last_modified_on']}}</td>
                    <td><input type="submit" name="metric_save" value="Save" class="metric_save"></td>
                    <td><input type="submit" name="metric_delete" value="Delete" class="delete"></td>
                </form>
            </tr>
            {% endfor %}
            <tr>
                <form action="/metrics" method="post">
                    <td><input type="text" size="18" name="m_name" value="" title="Metric name. Lowercase alphanumerics and underscores allowed." pattern="[a-z0-9_\.]+"></td>
                    <td><input type="text" size="3" name="m_pg_version_from" value="9.0" title="Version from"></td>
                    <td><textarea name="m_sql" cols="35" title="SQL for metric">SELECT (extract(epoch from now()) * 1e9)::int8 as epoch_ns, ...</textarea></td>
                    <td><textarea name="m_sql_su" cols="35" title="Privileged (superuser or pg_monitor grant) SQL for metric"></textarea></td>
                    <td><input type="text" size="12" name="m_comment" value=""  title="Comment"></td>
                    <td><input type="checkbox" name="m_is_active"  title="Is active?" checked></td>
                    <td><input type="checkbox" name="m_is_helper" title="Is helper?"></td>
                    <td><input type="checkbox" name="m_master_only" title="Master only?"></td>
                    <td><input type="checkbox" name="m_standby_only" title="Standby only?"></td>
                    <td><textarea name="ma_metric_attrs" cols="20" title="Metric attributes - will be applied to all version definitions. Leave empty to use existing attributes!">{"is_instance_level": false}</textarea></td>
                    <td><textarea name="m_column_attrs" cols="30" title="Column attributes. Use to specify Prometheus Gauge type columns. 'Gauge' means non-cumulative columns.">{"prometheus_all_gauge_columns": true}</textarea></td>
                    <td></td>
                    <td><input type="submit" name="metric_new" value="New"></td>
                    <td></td>
                </form>
            </tr>
        </tbody>
    </table>
    <div class="alert alert-info">
      <strong>NB! </strong>Metric fetching SQL-s should always have the "epoch_ns" column present (otherwise server time will be used). Additionally columns with "tag_" prefix will be
        turned into indexed tags in InfluxDB or stored in the indexed "$metric_name.tag_data" column for Postgres for fast access. Also "dbname" (DB unique name) column will always be added by the framework
    </div>
    <div class="alert alert-primary">
      <h4>Available metric attributes:</h4>
        <dl>
            <dt>is_instance_level (default: false)</dt>
            <dd>Instance level metrics can be cached and shared between multiple DBs of a single instance to reduce query load on server. Default caching period is 30s,
                use the --instance-level-cache-max-seconds (PW2_INSTANCE_LEVEL_CACHE_MAX_SECONDS env.) gatherer param to change or set to 0 to disable. Caching will only
                be applied to 'continuous' DB types and only if metric interval is bigger than the --instance-level-cache-max-seconds value.</dd>
            <dt>metric_storage_name</dt>
            <dd>Enables dynamic "renaming" of metrics at storage level, i.e. declaring almost similar metrics
                with different names but the data will be stored under one metric. Currently used (for out-of-the box metrics) only
                for the 'stat_statements_no_query_text' metric, to not to store actual query texts from the "pg_stat_statements"
                extension for more security sensitive instances.</dd>
            <dt>extension_version_based_overrides</dt>
            <dd>Enables to "switch out" the query text from some other metric based on some specific
                extension version. See 'reco_add_index' for an example definition.</dd>
            <dt>disabled_days</dt>
            <dd>Enables to "pause" metric gathering on specified days. See metric_attrs.yaml for "wal" for an example.</dd>
            <dt>disabled_times</dt>
            <dd>Enables to "pause" metric gathering on specified time intervals. e.g. "09:00-17:00" for business hours.
                NB! disabled_days / disabled_times can also be defined both on metric and host (host_attrs) level.</dd>
        </dl>
    </div>
    <div class="alert alert-secondary">
      <h4>Available column attributes:</h4>
        <dl>
            <dt>prometheus_all_gauge_columns (default: false}</dt>
            <dd>Only relevant for Prometheus output to correctly set the (suggested, not validated) metric type. GAUGE = value changing with every scrape, COUNTER = value is normally incremented (like most postgres statistics)</dd>
            <dt>prometheus_gauge_columns (default: [])</dt>
            <dd>Only relevant for Prometheus output to correctly set the (suggested, not validated) metric type. List of GAUGE  (value changing with every scrape) columns for the given metric. When not set all columns are considered to be of type COUNTER</dd>
            <dt>prometheus_ignored_columns (default: [])</dt>
            <dd>Only relevant for Prometheus output. For cases where we don't want some columns to be exposed</dd>
            <dt>disabled_days</dt>
            <dd>Enables to "pause" metric gathering on specified days. See metric_attrs.yaml for "wal" for an example.</dd>
            <dt>disabled_times</dt>
            <dd>Enables to "pause" metric gathering on specified time intervals. e.g. "09:00-17:00" for business hours.
                NB! disabled_days / disabled_times can also be defined both on metric and host (host_attrs) level.</dd>
        </dl>
    </div>
</div>

</div>

<script src="/static/jquery-3.5.1.min.js"></script>
<script src="/static/bootstrap-4.3.1-dist/js/bootstrap.min.js"></script>

<script>
    $( document ).ready(function() {
        $(".delete").click(function(e){
            var r = confirm("Delete?");
            if (r == false) {
                e.preventDefault();
            }
        });
        $("#new").click(function(e){
            if ($('#pc_name').val() == '') {
                alert('Preset config name is empty!');
                e.preventDefault();
            }
            pc_config = $('#pc_config').val()
            try {
                JSON.parse(pc_config);
            } catch (ex) {
                alert('Preset config is not valid JSON!');
                e.preventDefault();
            }
        });
        $(".metric_save").click(function(e){
            var master = $(this).parent().parent().find("[name='m_master_only']");
            var standby = $(this).parent().parent().find("[name='m_standby_only']");
            if (master.is(":checked") && standby.is(":checked")) {
                alert("A metric cannot be both 'Master only' and 'Standby only'!");
                e.preventDefault();
            }
        });
    });
</script>

</body>
</html>
